package common.core.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import common.core.constant.Constant;
import jxl.Workbook;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import okhttp3.*;
import okhttp3.FormBody.Builder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import javax.servlet.http.HttpServletRequest;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 工具类
 *
 * @author LiuBo
 * 判断/验证,类型的方法用is开头
 * 转换类型的方法用 convert开头
 * 添加类型的方法用add开头
 * 获取类型的方法以get开头
 * 设置类型的方法以set开头
 * 复制类型的用copy开头
 * 排序类型的方法用sort开头
 * 功能性方法用execute开头
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class CommonUtil {

    private static Logger log = LoggerFactory.getLogger(CommonUtil.class);

    public static final String PATH_PREPARED_STATEMENT_UUID = "\\{uuid\\}";// UUID路径占位符
    public static final String PATH_PREPARED_STATEMENT_DATE = "\\{date(\\(\\w+\\))?\\}";// 日期路径占位符
    public static final String COMMON_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    /********功能性方法用execute开头*********/
    /**
     * 字符串解密
     *
     * @param s
     * @return
     * @return?String
     * @author add by chengxw
     * @date 2013-5-31
     */
    public static String executeDecrypt(String s) {
        int iLen = 0;
        String sText = s;
        String sResult = "";
        //String sRtn = "";
        iLen = sText.length();
        for (int i = 1; i <= iLen; i++) {
            sResult = (char) (sText.substring(i - 1, i).codePointAt(0) - (2 * (iLen - i - 2))) + sResult;
        }
        return sResult;
    }

    /**
     * 字符串加密
     *
     * @param str
     * @return
     * @return?String
     * @author add by chengxw
     * @date 2013-5-31
     */
    public static String executeEncrypt(String str) {
        StringBuffer resStr = new StringBuffer();
        StringBuffer buf = new StringBuffer(str.trim());
        buf = buf.reverse();//字符串翻转
        for (int i = 1; i <= buf.length(); i++) {
            char c = (char) (((buf.substring(i - 1, i)).codePointAt(0)) + ((buf.length() - i - 2) * 2));
            resStr.append(c);
        }
        return resStr.toString();
    }

    /**
     * StringBuffer,append,":"->StringBuffer:append
     *
     * @param before
     * @param append
     * @param join
     */
    public static void join(StringBuffer before, Object append, String join) {
        if (isEmpty(before)) {
            before.append(append);
        } else {
            before.append(join).append(append);
        }
    }

    /**
     * ":",a,b,c-> a:b:c
     *
     * @param join
     * @param appends
     */
    public static String join(String join, String... appends) {
        StringBuffer sb = new StringBuffer();
        for (String append : appends) {
            if (isNotEmpty(sb)) {
                sb.append(join);
            }
            sb.append(append);
        }
        return sb.toString();
    }

    /**
     * JAVA 加密
     *
     * @param strSrc 需要加密人字符串，支持中文
     *               空位MD5，支持MD5 ,SHA-1 SHA-256
     * @return?String
     * @author add by x
     * @date 2013-6-8
     */
    public static String executeMD5(String strSrc) {
        return executeEncrypt(strSrc, null);
    }

    /**
     * JAVA 加密
     *
     * @param strSrc  需要加密人字符串，支持中文
     * @param encName 空位MD5，支持MD5 ,SHA-1 SHA-256
     * @return?String
     * @author add by x
     * @date 2013-6-8
     */
    public static String executeEncrypt(String strSrc, String encName) {
        MessageDigest md = null;
        String strDes = null;

        byte[] bt = strSrc.getBytes();
        try {
            if (isEmpty(encName)) {
                encName = "MD5";
            }
            md = MessageDigest.getInstance(encName);
            md.update(bt);
            strDes = bytes2Hex(md.digest()); // to HexString
        } catch (NoSuchAlgorithmException e) {
            log.error("加密 失败", e);
            return null;
        }
        return strDes;
    }


    /***********排序类型的方法用sort开头**************/

    /**
     * 对list中的数据按照字段field就进升序排序
     *
     * @param list
     * @param field
     */
    @SuppressWarnings("all")
    public static void sortAsc(List list, final String field) {
        if (list == null) {
            return;
        }
        Collections.sort(list, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                try {
                    Object obj = null;
                    Object obj2 = null;
                    if (o1 instanceof Map) {
                        obj = ((Map) o1).get(field);
                        if (CommonUtil.isEmpty(obj)) {
                            return -1;
                        }
                        obj2 = ((Map) o2).get(field);
                        if (CommonUtil.isEmpty(obj2)) {
                            return 1;
                        }
                    } else {
                        obj = ReflectUtil.getFieldValue(o1, field);
                        if (CommonUtil.isEmpty(obj)) {
                            return -1;
                        }
                        obj2 = ReflectUtil.getFieldValue(o2, field);
                        if (CommonUtil.isEmpty(obj2)) {
                            return 1;
                        }
                    }
                    if (obj instanceof String) {
                        return ((String) obj).compareTo((String) obj2);
                    } else if (obj instanceof Number) {
                        return ((Number) obj).longValue() - ((Number) obj2).longValue() > 0 ? 1 : -1;
                    } else if (obj instanceof Date) {
                        return ((Date) obj).getTime() - ((Date) obj2).getTime() > 0 ? 1 : -1;
                    } else {
                        throw new Exception("字段数据类型只能是String,Number和Date");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return 0;
            }
        });
    }

    /**
     * 对list中的数据按照字段field进行降序排序
     *
     * @param list
     * @param field
     */
    @SuppressWarnings("all")
    public static void sortDesc(List list, final String field) {
        if (list == null) {
            return;
        }
        Collections.sort(list, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                try {
                    Object obj = null;
                    Object obj2 = null;
                    if (o1 instanceof Map) {
                        obj = ((Map) o1).get(field);
                        if (CommonUtil.isEmpty(obj)) {
                            return 1;
                        }
                        obj2 = ((Map) o2).get(field);
                        if (CommonUtil.isEmpty(obj2)) {
                            return -1;
                        }
                    } else {
                        obj = ReflectUtil.getFieldValue(o1, field);
                        if (CommonUtil.isEmpty(obj)) {
                            return 1;
                        }
                        obj2 = ReflectUtil.getFieldValue(o2, field);
                        if (CommonUtil.isEmpty(obj2)) {
                            return -1;
                        }
                    }
                    if (obj instanceof String) {
                        return ((String) obj2).compareTo((String) obj);
                    } else if (obj instanceof Number) {
                        return ((Number) obj2).longValue() - ((Number) obj).longValue() > 0 ? 1 : -1;
                    } else if (obj instanceof Date) {
                        return ((Date) obj2).getTime() - ((Date) obj).getTime() > 0 ? 1 : -1;
                    } else {
                        throw new Exception("字段数据类型只能是String,Number和Date");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return 0;
            }
        });
    }

    /**
     * 对list中的数据进行升序排序
     *
     * @param list
     */
    @SuppressWarnings("all")
    public static void sortAsc(List list) {
        if (isEmpty(list)) {
            return;
        }
        Collections.sort(list, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                try {
                    Object obj = o1;
                    if (isEmpty(obj)) {
                        return -1;
                    }
                    Object obj2 = o2;
                    if (isEmpty(obj2)) {
                        return 1;
                    }
                    if (obj instanceof String) {
                        return ((String) obj).compareTo((String) obj2);
                    } else if (obj instanceof Number) {
                        return ((Number) obj).longValue() - ((Number) obj2).longValue() > 0 ? 1 : -1;
                    } else if (obj instanceof Date) {
                        return ((Date) obj).getTime() - ((Date) obj2).getTime() > 0 ? 1 : -1;
                    } else {
                        throw new Exception("字段数据类型只能是String,Number和Date");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return 0;
            }
        });
    }

    /**
     * 对list中的数据进行降序排序
     *
     * @param list
     */
    @SuppressWarnings("all")
    public static void sortDesc(List list) {
        if (isEmpty(list)) {
            return;
        }
        Collections.sort(list, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                try {
                    Object obj = o1;
                    if (isEmpty(obj)) {
                        return 1;
                    }
                    Object obj2 = o2;
                    if (isEmpty(obj2)) {
                        return -1;
                    }
                    if (obj instanceof String) {
                        return ((String) obj2).compareTo((String) obj);
                    } else if (obj instanceof Number) {
                        return ((Number) obj2).longValue() - ((Number) obj).longValue() > 0 ? 1 : -1;
                    } else if (obj instanceof Date) {
                        return ((Date) obj2).getTime() - ((Date) obj).getTime() > 0 ? 1 : -1;
                    } else {
                        throw new Exception("字段数据类型只能是String,Number和Date");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return 0;
            }
        });
    }

    /*************** 复制类型的用copy开头 ******************/

    @SuppressWarnings("all")
    public static <T> List<T> copyListBean(List list_source, Class target_entity_class, String... ignores) {
        if (isEmpty(list_source)) {
            return new ArrayList<T>();
        }
        List<T> ts = new ArrayList<T>();
        for (Object obj : list_source) {
            T target;
            try {
                target = (T) target_entity_class.newInstance();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                target = null;
            }
            target = copyBean(obj, target, ignores);
            ts.add(target);
        }
        return ts;
    }


    public static <T> T copyBean(Object source, T t, String... ignores) {
        T target;
        try {
            target = (T) t.getClass().newInstance();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
        if (isEmpty(source)) {
            return null;
        }
        try {
            copyBeanProperties(source, target, ignores);
        } catch (Exception e) {
            return null;
        }
        return target;
    }

    public static <T> T copyBean(Object source, Class<T> clazz, String... ignores) {
        T target;
        try {
            target = (T) clazz.newInstance();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
        if (isEmpty(source)) {
            return null;
        }
        try {
            copyBeanProperties(source, target, null);
        } catch (Exception e) {
            return null;
        }
        return target;
    }

    public static <T> T copyBean(T source, String... ignores) {
        T target;
        try {
            target = (T) source.getClass().newInstance();
        } catch (Exception e) {
            return null;
        }
        if (isEmpty(source)) {
            return null;
        }
        try {
            copyBeanProperties(source, target, ignores);
        } catch (Exception e) {
            return null;
        }
        return target;
    }


    private static void copyBeanProperties(Object source, Object target, String[] ignores) throws Exception {
        Class<?> actualEditable = target.getClass();
        PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(actualEditable);
        List<String> ignoreList = (ignores != null) ? Arrays.asList(ignores) : null;
        for (PropertyDescriptor targetPd : targetPds) {
            if (targetPd.getWriteMethod() != null &&
                    (ignores == null || (!ignoreList.contains(targetPd.getName())))) {
                PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
                if (sourcePd != null && sourcePd.getReadMethod() != null) {
                    Method readMethod = sourcePd.getReadMethod();
                    if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                        readMethod.setAccessible(true);
                    }
                    Object value = readMethod.invoke(source);
                    Method writeMethod = targetPd.getWriteMethod();
                    if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                        writeMethod.setAccessible(true);
                    }
                    String type = writeMethod.getParameterTypes()[0].getSimpleName();//参数类型
                    if ("boolean".equals(type)) {
                        boolean booleanVal = false;
                        if ("1".equals(value.toString())) {
                            booleanVal = true;
                        }
                        writeMethod.invoke(target, new Object[]{Boolean.valueOf(booleanVal)});
                        continue;
                    }
                    if ("Timestamp".equals(type)) {
                        if (CommonUtil.isNotEmpty(value)) {
                            Date date = (Date) value;
                            Timestamp ts = new Timestamp(date.getTime());
                            writeMethod.invoke(target, new Object[]{ts});
                        }
                        continue;
                    }
                    writeMethod.invoke(target, value);
                }
            }
        }
    }
    /********** 设置类型的方法以set开头 **************/


    /************* 获取类型的方法以get开头 ************/
    /**
     * 将汉字转换为全拼
     *
     * @param str
     * @return String
     */
    public static String getPinYin(String str) {
        if (isEmpty(str)) {
            return "";
        }
        return PinYinUtil.getPinYin(str);
    }

    /**
     * 清空STRINGBUFFER
     *
     * @param sb
     * @return void
     */
    public static void getClearStringBuffer(StringBuffer sb) {
        sb.delete(0, sb.length());
    }

    /**
     * 对文件流输出下载的中文文件名进行编码 屏蔽各种浏览器版本的差异性
     */
    public static String getChineseDownloadFileName(HttpServletRequest request, String pFileName) {
        String agent = request.getHeader("USER-AGENT");
        try {
            if (null != agent && -1 != agent.indexOf("MSIE")) {
                pFileName = URLEncoder.encode(pFileName, "utf-8");
            } else {
                pFileName = new String(pFileName.getBytes("utf-8"), "iso8859-1");
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return pFileName;
    }

    /**
     * 根据日期获取星期
     *
     * @param strdate
     * @return
     */
    public static String getWeekDayByDate(String strdate) {
        final String dayNames[] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        SimpleDateFormat sdfInput = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        Date date = new Date();
        try {
            date = sdfInput.parse(strdate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        calendar.setTime(date);
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        if (dayOfWeek < 0) {
            dayOfWeek = 0;
        }
        return dayNames[dayOfWeek];
    }

    /**
     * 获得今天周几
     *
     * @return int   Calender.MONDAY 星期一  Calender.THURSDAY 星期二  ...
     */
    public static int getDayOfWeek() {
        return Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 获得指定时间是周几
     *
     * @return int   Calender.MONDAY 星期一  Calender.THURSDAY 星期二  ...
     */
    public static int getDayOfWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 获得随即颜色
     *
     * @return String
     * @author add by x@2012-10-30
     */
    public static String getRandom(int count) {
        String S = "0123456789ABCDEF";
        Random r = new Random();
        String tmp = "";
        for (int i = 0; i < count; i++) {
            int index = r.nextInt(S.length());
            tmp += S.charAt(index);
        }
        return tmp;
    }

    /**
     * 获得随机数字
     *
     * @param count 字符长度
     * @return
     */
    public static String getRandomNumber(int count) {
        String S = "0123456789";
        Random r = new Random();
        String tmp = "";
        for (int i = 0; i < count; i++) {
            int index = r.nextInt(S.length());
            tmp += S.charAt(index);
        }
        return tmp;
    }

    public static String getCurrentDateTime() {
        SimpleDateFormat format = new SimpleDateFormat(COMMON_DATE_FORMAT);
        return format.format(new Date(System.currentTimeMillis()));
    }

    public static String getCurrentDateTimeByFormat(String fmt) {
        SimpleDateFormat format = new SimpleDateFormat(fmt);
        return format.format(new Date(System.currentTimeMillis()));
    }

    private static Map<String, SimpleDateFormat> dateFormatMap = new HashMap<>();

    public static String getDateFormat(Object date, String fmt) {
        SimpleDateFormat format = dateFormatMap.get(fmt);
        if (isEmpty(format)) {
            format = new SimpleDateFormat(fmt);
            dateFormatMap.put(fmt, format);
        }
        return format.format(date);
    }

    /**
     * 随机获取UUID字符串(无中划线)
     *
     * @return UUID字符串
     */
    public static String getUUID() {
        String uuid = UUID.randomUUID().toString();
        return uuid.substring(0, 8) + uuid.substring(9, 13) + uuid.substring(14, 18) + uuid.substring(19, 23) + uuid.substring(24);
    }


    /**
     * 描述
     *
     * @param date1 开始时间
     * @param date2 结束时间
     * @return 返回集合
     * @author zhulc
     * 2013-4-11 下午04:41:45
     */
    @SuppressWarnings("static-access")
    public static List<String> getEndDate(Date date1, Date date2) {
        List<String> list = new ArrayList<String>();
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        long time1 = cal1.getTimeInMillis();
        long time2 = cal2.getTimeInMillis();
        int betweendays = (int) ((time2 - time1) / (1000 * 3600 * 24));
        cal1.add(Calendar.DATE, 1);
        SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
        //  System.out.println("获取cal1:"+date.format(cal2.getTime()));
        for (int i = 0; i <= betweendays; i++) {
            Calendar caA = Calendar.getInstance();
            caA.setTime(date1);
            //System.out.println("i:"+i);
            //添加日期
            caA.add(Calendar.DATE, i);
            Calendar cab = Calendar.getInstance();
            cab.setTime(caA.getTime());
            String week = "";
            int weekDay = cab.get(Calendar.DAY_OF_WEEK) - 1;
            switch (weekDay) {
                case 0:
                    week = "周日";
                    break;
                case 1:
                    week = "周一";
                    break;
                case 2:
                    week = "周二";
                    break;
                case 3:
                    week = "周三";
                    break;
                case 4:
                    week = "周四";
                    break;
                case 5:
                    week = "周五";
                    break;
                default:
                    week = "周六";
                    break;
            }
            StringBuffer dates = new StringBuffer();
            dates.append(date.format(caA.getTime()));
            dates.append(" ");
            dates.append(week);
            list.add(dates.toString());
            //	System.out.println("获取天数"+date.format(caA.getTime()));
        }
        return list;
    }

    //获取MAC地址的方法
    public static String getMACAddress(InetAddress ia) throws Exception {
        //获得网络接口对象（即网卡），并得到mac地址，mac地址存在于一个byte数组中。
        byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
        //下面代码是把mac地址拼装成String
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) {
                sb.append("-");
            }
            //mac[i] & 0xFF 是为了把byte转化为正整数
            String s = Integer.toHexString(mac[i] & 0xFF);
            sb.append(s.length() == 1 ? 0 + s : s);
        }
        //把字符串所有小写字母改为大写成为正规的mac地址并返回
        return sb.toString().toUpperCase();
    }

    public static String getMAC() {
        String macAddress = "";
        try {
            InetAddress ia = InetAddress.getLocalHost();//获取本地IP对象
            macAddress = getMACAddress(ia);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return macAddress;
    }

    /**
     * getIntervalDays
     * 两个日期间隔的天数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int getIntervalDays(Date startDate, Date endDate) {
        int intervalDays = 0;
        Calendar calendarStartDate = Calendar.getInstance();
        Calendar calendarEndDate = Calendar.getInstance();
        calendarStartDate.setTime(startDate);
        calendarEndDate.setTime(endDate);
        //如果开始时间大于结束时间返回0
        if (calendarStartDate.after(calendarEndDate)) {
            return 0;
        } else {
            int intervalYears = calendarEndDate.get(Calendar.YEAR) - calendarStartDate.get(Calendar.YEAR);
            intervalDays = calendarEndDate.get(Calendar.DAY_OF_YEAR) - calendarStartDate.get(Calendar.DAY_OF_YEAR);
            for (int i = 0; i < intervalYears; i++) {
                calendarStartDate.set(Calendar.YEAR, (calendarStartDate.get(Calendar.YEAR) + 1));
                intervalDays += calendarStartDate.getMaximum(Calendar.DAY_OF_YEAR);
            }
            return intervalDays;
        }
    }


    /**
     * 获取集合中对象的值转换成list并且返回
     *
     * @param collection
     * @param key
     * @return
     * @throws Exception
     */
    public static <E> List<E> getCollectionFieldToList(Collection collection, String key) {
        if (key.contains("_")) {
            key = dbForDBToFistLowercaseHump(key);
        }
        List<E> list = new ArrayList<E>();
        if (collection == null) {
            return list;
        } else {
            try {
                for (Object t : collection) {
                    if (t instanceof Map) {
                        list.add((E) ((Map) t).get(key));
                    } else {//实体类
                        list.add((E) getFieldValue(t, key));
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new CustomizeRuntimeException("获取集合对象属性[" + key + "]失败", collection);
            }
        }
        return list;
    }

    /**
     * 获取集合中对象的值转换成list并且返回
     *
     * @param collection
     * @param key
     * @return
     * @throws Exception
     */
    public static <E> Map<String, E> getCollectionFieldToMap(Collection<E> collection, String key) {
        Map<String, E> result = new HashMap<String, E>();
        if (collection == null) {
            return result;
        } else {
            try {
                for (Object t : collection) {
                    if (t instanceof Map) {
                        Map map = (Map) t;
                        result.put((String) map.get(key), (E) t);
                    } else {//实体类
                        result.put(getFieldValue(t, key), (E) t);
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new CustomizeRuntimeException("获取集合对象属性[" + key + "]失败", collection);
            }
        }
        return result;
    }

    /**
     * @param collection
     * @param key
     * @param value
     * @param <K>
     * @param <E>
     * @return
     */
    public static <K, E> Map<K, E> getCollectionKVToMap(Collection collection, String key, String value) {
        Map<K, E> result = new HashMap<K, E>();
        if (collection == null) {
            return result;
        } else {
            try {
                for (Object t : collection) {
                    if (t instanceof Map) {
                        Map map = (Map) t;
                        result.put((K) map.get(key), (E) map.get(value));
                    } else {//实体类
                        result.put((K) getFieldValue(t, key), (E) getFieldValue(t, value));
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new CustomizeRuntimeException("获取集合对象属性[" + key + "]失败", collection);
            }
        }
        return result;
    }

    /**
     * 获取集合中对象的值转换成list并且返回
     *
     * @param collection
     * @param key
     * @return
     * @throws Exception
     */
    public static <K, E> Map<K, List<E>> getCollectionFieldToListObjectMap(Collection collection, String key) {
        Map<K, List<E>> result = new HashMap<K, List<E>>();
        if (collection == null) {
            return result;
        } else {
            try {
                for (Object t : collection) {
                    if (t instanceof Map) {
                        Map map = (Map) t;
                        List<E> list = result.get((K) map.get(key));
                        if (isEmpty(list)) {
                            list = new ArrayList<E>();
                        }
                        list.add((E) t);
                        result.put((K) map.get(key), list);
                    } else {//实体类
                        List<E> list = result.get((K) getFieldValue(t, key));
                        if (isEmpty(list)) {
                            list = new ArrayList<E>();
                        }
                        list.add((E) t);
                        result.put((K) getFieldValue(t, key), list);
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new CustomizeRuntimeException("获取集合对象属性[" + key + "]失败", collection);
            }
        }
        return result;
    }

    /**
     * 获取集合中对象的值转换成list并且返回
     *
     * @param collection
     * @param key
     * @return
     * @throws Exception
     */
    public static <E> Set<E> getCollectionFieldToSet(Collection collection, String key) {
        Set<E> list = new HashSet<E>();
        if (collection == null) {
            return list;
        } else {
            try {
                for (Object t : collection) {
                    if (t instanceof Map) {
                        list.add((E) ((Map) t).get(key));
                    } else {//实体类
                        list.add((E) getFieldValue(t, key));
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new CustomizeRuntimeException("获取集合对象属性[" + key + "]失败", collection);
            }
        }
        return list;
    }

    /**
     * 获取一个 heder+yyyyMMddHHmmssSSS+4位随机数
     *
     * @param heder
     * @return
     */
    public static String getBillNumber(String heder) {
        return heder + new SimpleDateFormat("yyMMddHHmmssSSS").format(new Date()) + getRandomNumber(4);
    }

    /**
     * @param @param  transNo 单据号类型
     * @param @param  branchNo  操作员的所属门店
     * @param @return
     * @return String    返回一个随机生成的单据号
     * @throws
     * @Title: generateDocumentNum
     * @Description: 生成单据号
     */
    public static String getSheetNo(String transNo, String branchNo) {
        String documentId = transNo + getCurrentDateTimeByFormat("yyMMddHHmm") + getRandomNumber(6);
        return documentId;
    }

    /**
     * <p>
     * 反射对象获取泛型
     * </p>
     *
     * @param clazz 对象
     * @param index 泛型所在位置
     * @return Class
     */
    public static Class getSuperClassGenricType(final Class clazz, final int index) {
        Type genType = clazz.getGenericSuperclass();
        if (!(genType instanceof ParameterizedType)) {
            log.warn(String.format("Warn: %s's superclass not ParameterizedType", clazz.getSimpleName()));
            return Object.class;
        }
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        if (index >= params.length || index < 0) {
            log.warn(String.format("Warn: Index: %s, Size of %s's Parameterized Type: %s .", index, clazz.getSimpleName(),
                    params.length));
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
            log.warn(String.format("Warn: %s not set the actual class on superclass generic parameter", clazz.getSimpleName()));
            return Object.class;
        }
        return (Class) params[index];
    }

    /**
     * <p>
     * 获取该类的所有属性列表
     * </p>
     *
     * @param clazz 反射类
     * @return
     */
    public static Map<String, Field> getFieldMap(Class<?> clazz) {
        List<Field> fieldList = getFieldList(clazz);
        Map<String, Field> fieldMap = Collections.emptyMap();
        if (isNotEmpty(fieldList)) {
            fieldMap = new LinkedHashMap<>();
            for (Field field : fieldList) {
                fieldMap.put(field.getName(), field);
            }
        }
        return fieldMap;
    }

    /**
     * <p>
     * 获取该类的所有属性列表
     * </p>
     *
     * @param clazz 反射类
     * @return
     */
    public static List<Field> getFieldList(Class<?> clazz) {
        if (null == clazz) {
            return null;
        }
        List<Field> fieldList = new LinkedList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            /* 过滤静态属性 */
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            /* 过滤 transient关键字修饰的属性 */
            if (Modifier.isTransient(field.getModifiers())) {
                continue;
            }
            fieldList.add(field);
        }
        /* 处理父类字段 */
        Class<?> superClass = clazz.getSuperclass();
        if (superClass.equals(Object.class)) {
            return fieldList;
        }
        /* 排除重载属性 */
        return excludeOverrideSuperField(fieldList, getFieldList(superClass));
    }

    /**
     * 获取当前类的所有field 字段
     *
     * @param clazz
     * @return
     */
    public static List<Field> getCurrentFieldList(Class<?> clazz) {
        if (null == clazz) {
            return null;
        }
        List<Field> fieldList = new LinkedList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            /* 过滤静态属性 */
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            /* 过滤 transient关键字修饰的属性 */
            if (Modifier.isTransient(field.getModifiers())) {
                continue;
            }
            fieldList.add(field);
        }
        return fieldList;
    }

    /**
     * <p>
     * 排序重置父类属性
     * </p>
     *
     * @param fieldList      子类属性
     * @param superFieldList 父类属性
     */
    public static List<Field> excludeOverrideSuperField(List<Field> fieldList, List<Field> superFieldList) {
        // 子类属性
        Map<String, Field> fieldMap = new HashMap<>();
        for (Field field : fieldList) {
            fieldMap.put(field.getName(), field);
        }
        for (Field superField : superFieldList) {
            if (null == fieldMap.get(superField.getName())) {
                // 加入重置父类属性
                fieldList.add(superField);
            }
        }
        return fieldList;
    }

    public static Object getClassDeclaredField(Object obj, String filedText) throws Exception {
        Field field = obj.getClass().getDeclaredField(filedText);
        if (field == null) {
            return null;
        }
        field.setAccessible(true);
        return field.get(obj);
    }


    public static <T> T getSuperclassDeclaredField(Object obj, String filedText) throws Exception {
        Field field = obj.getClass().getSuperclass().getDeclaredField(filedText);

        if (field == null) {
            return null;
        }

        field.setAccessible(true);
        return (T) field.get(obj);
    }

    /**
     * 利用反射设置指定对象的指定属性为指定的值
     *
     * @param obj        目标对象
     * @param fieldName  目标属性
     * @param fieldValue 目标值
     */
    public static <T> void setFieldValue(Object obj, String fieldName, T fieldValue) {
        Field field = ReflectUtil.getField(obj, fieldName);
        if (field != null) {
            try {
                field.setAccessible(true);
                field.set(obj, fieldValue);
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
            }
        }
    }

    /**
     * 获取传入的对象,获取字段的值(getXXX)
     *
     * @param obj
     * @param fieldName
     * @return
     */
    public static <T> T getFieldValue(Object obj, String fieldName) {
        Object result = null;
        Field field = ReflectUtil.getField(obj, fieldName);
        if (field != null) {
            field.setAccessible(true);
            try {
                result = field.get(obj);
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
            }
        }
        return (T) result;
    }

    /**
     * 向指定URL发送GET方法的请求
     *
     * @param host + address 发送请求的URL
     * @param data 请求参数
     * @return URL 所代表远程资源的响应结果
     */
    public static String sendGetParamData(String host, String address, String data) {
        String url = null;
        if (host.endsWith("/") || address.startsWith("/")) {
            url = host + address;
        } else {
            url = host + "/" + address;
        }
        return sendPostParamData(url, data);
    }

    public static String sendGetParamData(String url, String data) {
        try {
            OkHttpClient client = new OkHttpClient();
            if (CommonUtil.isNotEmpty(data)) {
                url = url + "?data=" + data;
            }

            Request request = new Request.Builder()
                    .url(url)
                    .build();
            Call call = client.newCall(request);
            Response response = call.execute();
            return response.body().string();
        } catch (Exception e) {
            log.error("GET 发送错误 url:{}", url, e);
            return CommonUtil.convertObjectToJson(Result.fail(e.getMessage()));
        }
    }

    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param host +address 发送请求的 URL
     * @param data 请求参数
     * @return 所代表远程资源的响应结果
     */
    public static String sendPostParamData(String host, String address, String data) {
        String url = null;
        if (host.endsWith("/") || address.startsWith("/")) {
            url = host + address;
        } else {
            url = host + "/" + address;
        }
        return sendPostParamData(url, data);
    }

    public static String sendPostParamData(String url, String data) {
        try {
            OkHttpClient client = new OkHttpClient();

            RequestBody body = new Builder()
                    .add("data", data)
                    .build();

            Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .build();
            Call call = client.newCall(request);
            Response response = call.execute();
            return response.body().string();
        } catch (Exception e) {
            log.error("POST 发送错误 url:{}", url, e);
            return CommonUtil.convertObjectToJson(Result.fail(e.getMessage()));
        }
    }

    public static String sendPost(String url, Map<String, String> param) {
        OkHttpClient client = new OkHttpClient();
        Builder builder = new Builder();
        if (CommonUtil.isNotEmpty(param)) {
            for (String key : param.keySet()) {
                builder.add(key, param.get(key));
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .build();
        try {
            Call call = client.newCall(request);
            return call.execute().body().string();
        } catch (Exception e) {
            log.error("post错误", e);
            return "{}";
        }
    }

    /********** 添加类型的方法用add开头 **********/
    /**
     * 日期加一个月
     *
     * @param date 日期 格式
     * @return
     * @return?date
     * @author add by jiaxj
     * @date 2014-7-30
     */
    public static Date addDateMonth(Date date, int months) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, months);
        return calendar.getTime();
    }

    /**
     * 日期加天数
     *
     * @param date 日期 格式yyyy-mm-dd HH:mm:ss
     * @param days 天数
     * @return
     * @return?String yyyy-mm-dd HH:mm:ss
     * @author add by zlc
     * @date 2013-12-10
     */
    public static String addDate(String date, int days) {
        SimpleDateFormat format = new SimpleDateFormat(COMMON_DATE_FORMAT);
        try {
            Date da = format.parse(date);
            Calendar ca = Calendar.getInstance();
            ca.setTime(da);
            ca.add(Calendar.DATE, days);// 为增加的天数
            da = ca.getTime();
            String backTime = format.format(da);
            return backTime;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 添加天数
     *
     * @param data
     * @param days
     * @return
     */
    public static Date addDate(Date data, int days) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(data);
        ca.add(Calendar.DATE, days);// 为增加的天数
        data = ca.getTime();
        return data;
    }

    /**
     * 添加一个元素到已有的数据里面去
     *
     * @param array
     * @param element
     * @return
     */
    public static <T> T[] addArrayElement(T[] array, T element) {
        Class type;
        if (array != null) {
            type = array.getClass();
        } else if (element != null) {
            type = element.getClass();
        } else {
            type = Object.class;
        }
        T[] newArray = (T[]) copyArrayGrow1(array, type);
        newArray[newArray.length - 1] = element;
        return newArray;
    }

    /*************** 转换类型的方法用 convert开头 *******************/

    public static List<Integer> convertStringToIntegerList(String... strs) {
        if (isEmpty(strs)) {
            return null;
        } else {
            List<Integer> list = new ArrayList<Integer>();
            for (String str : strs) {
                list.add(Integer.valueOf(str));
            }
            return list;
        }
    }

    public static BigDecimal convertStringToBigDecimal(String str) {
        if (isEmpty(str)) {
            return BigDecimal.ZERO;
        } else {
            return new BigDecimal(str.trim());
        }
    }

    /**
     * 将一个 Map 对象转化为一个 JavaBean
     *
     * @param clazz 要转化的类型
     * @param map   包含属性值的 map
     * @return 转化出来的 JavaBean 对象
     * @throws IntrospectionException    如果分析类属性失败
     * @throws IllegalAccessException    如果实例化 JavaBean 失败
     * @throws InstantiationException    如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
    public static <T> T convertMapToBean(Map map, Class<T> clazz) {
        if (map == null) {
            return null;
        }
        Object obj;
        try {
            obj = clazz.newInstance();
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                Method setter = property.getWriteMethod();
                try {
                    if (setter != null) {
                        Object object = map.get(property.getName());
                        if (isNotEmpty(object)) {
                            setter.invoke(obj, object);
                        }
                    }
                } catch (Exception e) {
                    log.error(property.getName() + "[" + map.get(property.getName()).getClass() + "]不能转换成-->" + property.getPropertyType());
                    throw e;
                }
            }
            return (T) obj;
        } catch (Exception e) {
            log.error("Map --> Object 转换错误", e);
            return null;
        }
    }

    /**
     * format yyyy-MM-dd HH:mm:ss
     *
     * @param str
     * @return
     * @throws ParseException
     */
    public static Date convertStringToDate(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(COMMON_DATE_FORMAT);
        String strDate = str;
        return sdf.parse(strDate);
    }

    /**
     * format yyyy-MM-dd
     *
     * @param str
     * @return
     * @throws ParseException
     */
    public static Date convertStringToOnlyDate(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String strDate = str;
        return sdf.parse(strDate);
    }

    /**
     * @param str format
     * @return
     * @throws ParseException
     */
    public static Date convertStringToDate(String str, String format) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        String strDate = str;
        return sdf.parse(strDate);
    }

    /**
     * 将对象转换为JSON字符串
     *
     * @param object 对象
     */
    public static String convertObjectToJson(Object object) {
        if (isEmpty(object)) {
            return null;
        }
        try {
            return JSONObject.toJSONString(object);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public static String convertDateToString(Date date, String format) {
        log.debug("开始转换。。。");
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * 将JSON字符串转换为对象
     *
     * @param json  JSON字符串
     * @param clazz 对象类型
     */
    public static <T> T convertJsonToObject(String json, Class clazz, boolean isArray) {
        if (isEmpty(json) || isEmpty(clazz)) {
            return null;
        }
        json = json.trim();
        if (json.startsWith("[")) {
            if (isArray) {
                return (T) JSONArray.parseArray(json, clazz).toArray((T[]) Array.newInstance(clazz, 0));
            }
            return (T) JSONArray.parseArray(json, clazz);
        } else if (json.startsWith("{")) {
            return (T) JSONObject.parseObject(json, clazz);
        }

        return null;
    }

    /**
     * 将JSON字符串转换为对象
     *
     * @param json  JSON字符串
     * @param clazz 对象类型
     */
    public static <T> T convertJsonToObject(String json, Class clazz) {
        return convertJsonToObject(json, clazz, false);
    }

    /**
     * 将一个 JavaBean 对象转化为一个  Map
     *
     * @param bean 要转化的JavaBean 对象
     * @return 转化出来的  Map 对象
     * @throws IntrospectionException    如果分析类属性失败
     * @throws IllegalAccessException    如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
    public static <T> Map<String, T> convertBeanToMap(Object bean) {
        try {
            if (isEmpty(bean)) {
                return null;
            }
            Map returnMap = new HashMap();
            Class type = bean.getClass();
            BeanInfo beanInfo = Introspector.getBeanInfo(type);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (!"class".equals(propertyName)) {
                    Method readMethod = descriptor.getReadMethod();
                    Object value = readMethod != null ? readMethod.invoke(bean) : null;
                    returnMap.put(propertyName, value);
                }
            }
            return returnMap;
        } catch (Exception e) {
            log.error(bean.getClass().getName() + " to Map 转换错误 ," + e.getMessage(), e);
            throw new CustomizeRuntimeException(bean.getClass().getName() + " to Map 转换错误");
        }
    }

    public static List<Map<String, Object>> convertCollectionBeanToCollectionMap(Collection collections) {
        if (isEmpty(collections)) {
            return null;
        }
        List<Map<String, Object>> list = new ArrayList<>();
        for (Object obj : collections) {
            list.add(convertBeanToMap(obj));
        }
        return list;

    }


    /**
     * 将驼峰数据转换为正常数据，去除_ 变大写
     * BdItemInfo--->bd_item_info或者bdItemInfo--->bd_item_info
     *
     * @param map
     * @return
     */
    public static <V> Map<String, V> convertMapFieldToFistLowercaseHump(Map<String, V> map) {
        if (isEmpty(map)) {
            return map;
        }
        Map<String, V> result = new HashMap<String, V>();
        for (String key : map.keySet()) {
            result.put(dbForDBToFistLowercaseHump((String) key), map.get(key));
        }
        return result;
    }

    public static <V> List<Map<String, V>> convertCollectionMapFieldToFistLowercaseHump(List<Map<String, V>> list) {
        if (isEmpty(list)) {
            return list;
        }
        List<Map<String, V>> result = new ArrayList<Map<String, V>>();
        for (Map<String, V> map : list) {
            result.add(convertMapFieldToFistLowercaseHump(map));
        }
        return result;
    }

    /**
     * 把传入的字符串 转化成where xxx in (xxx) 的形式，
     *
     * @param str 1,2,3,4
     * @return String
     * @return (' 1 ', ' 2 ', ' 3 ', ' 4 ')
     * @author add by x@2012-9-17
     */
    public static String convertContainCommaStringToWhereIn(String str) {
        if (str == null || "".equals(str)) {
            return "('')";
        }

        if (str.indexOf(",") > 0) {
            String[] list = str.split(",");
            StringBuffer sb = new StringBuffer("(");
            for (int i = 0; i < list.length; i++) {
                sb.append("'" + list[i] + "'");
                if (i != list.length - 1) {
                    sb.append(",");
                }
            }
            sb.append(")");
            return sb.toString();
        } else {
            return "('" + str + "')";
        }
    }

    /******************  判断/验证,类型的方法用is开头  ********************/
    public static boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }

    public static boolean isEquals(Object a, Object b) {
        if (isEmpty(a)) {
            return false;
        }
        if (isEmpty(b)) {
            return false;
        }
        if (a.equals(b)) {
            return true;
        }
        return false;
    }

    public static <T> boolean isNotEquals(T a, T b) {
        if (isEmpty(a)) {
            return false;
        }
        if (isEmpty(b)) {
            return false;
        }
        if (a.equals(b)) {
            return false;
        }
        return true;
    }

    public static boolean isNotEqualsIntegerZero(Integer a) {
        if (isEmpty(a)) {
            return false;
        }
        if (a.equals(0)) {
            return false;
        }
        return true;
    }

    public static boolean isEqualsIntegerZero(Integer a) {
        if (isEmpty(a)) {
            return false;
        }
        if (a.equals(0)) {
            return true;
        }
        return false;
    }

    /**
     * 判断对象是否Empty(null或元素为0)<br>
     * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
     *
     * @param object 待检查对象
     * @return boolean 返回的布尔值
     */
    public static boolean isEmpty(Object object) {
        if (object == null) {
            return true;
        } else if (object instanceof String) {
            if (StringUtils.isBlank((String) object)) {
                return true;
            }
        } else if (object instanceof Collection) {
            if (((Collection) object).size() == 0) {
                return true;
            }
        } else if (object instanceof Map) {
            if (((Map) object).size() == 0) {
                return true;
            }
        } else if (object instanceof StringBuffer) {
            if (((StringBuffer) object).length() == 0) {
                return true;
            }
        } else if (object instanceof StringBuilder) {
            if (((StringBuilder) object).length() == 0) {
                return true;
            }
        } else if (object.getClass().isArray()) {
            if (Array.getLength(object) == 0) {
                return true;
            }
        }

        return false;
    }

    /**
     * 为数字类型
     *
     * @param obj
     * @return
     */
    public static Boolean isNumberForObject(Object obj) {
        Boolean flag = false;
        if (obj instanceof Number) {
            flag = true;
        }
        return flag;
    }

    /**
     * 为数字类型
     *
     * @param obj
     * @return
     */
    public static Boolean isNotNumberForObject(Object obj) {
        if (obj instanceof Number) {
            return false;
        }
        return true;
    }

    /**
     * 是否为时间类型
     *
     * @param obj
     * @return
     */
    public static Boolean isTimeForObject(Object obj) {
        if (obj instanceof Date) {
            return true;
        }
        return false;
    }

    /**
     * 是否为数字类型
     *
     * @param clazz
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws Exception
     */
    public static Boolean isNumberForClass(Class clazz) {
        try {
            if (clazz.newInstance() instanceof Number) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }

    /**
     * 是否为日期类型
     *
     * @param clazz
     * @return
     * @throws Exception
     */
    public static Boolean isTimeForClass(Class clazz) {
        try {
            if (clazz.newInstance() instanceof Date) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }

    public static String isEmptyReturnNull(String param) {
        return isEmpty(param) ? null : param;
    }

    public static BigDecimal isEmptyReturnNull(BigDecimal param) {
        return isEmpty(param) ? null : param;
    }

    public static Object isEmptyReturnNull(Object param) {
        return isEmpty(param) ? null : param;
    }

    public static String isEmptyReturnEmpty(Object param) {
        if (param instanceof Date) {
            param = convertDateToString((Date) param, COMMON_DATE_FORMAT);
        }
        return isEmpty(param) ? "" : (String) param;
    }

    public static BigDecimal isEmptyReturnZero(BigDecimal param) {
        return isEmpty(param) ? BigDecimal.ZERO : param;
    }

    public static int isEmptyReturnZero(List param) {
        return isEmpty(param) ? 0 : param.size();
    }

    public static <T> T isEmptyReturn(T param, T returnValue) {
        return isEmpty(param) ? returnValue : param;
    }

    public static <T> T isEmptyReturn(Object IF, T empty, T notEmpty) {
        return isEmpty(IF) ? empty : notEmpty;
    }

    /*******私有方法区域*********/

    private static Object copyArrayGrow1(Object array, Class newArrayComponentType) {
        if (array != null) {
            int arrayLength = Array.getLength(array);
            Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);
            System.arraycopy(array, 0, newArray, 0, arrayLength);
            return newArray;
        }
        return Array.newInstance(newArrayComponentType, 1);
    }

    private static String bytes2Hex(byte[] bts) {
        String des = "";
        String tmp = null;
        for (int i = 0; i < bts.length; i++) {
            tmp = (Integer.toHexString(bts[i] & 0xFF));
            if (tmp.length() == 1) {
                des += "0";
            }
            des += tmp;
        }
        return des;
    }

    public static boolean isIn(String object, Object... targets) {
        if (isEmpty(object) || isEmpty(targets) || targets.length == 0) {
            return false;
        }
        for (Object obj : targets) {
            if (object.equals(obj)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取访问者IP
     * 在一般情况下使用Request.getRemoteAddr()即可，但是经过nginx等反向代理软件后，这个方法会失效。
     * <p>
     * 本方法先从Header中获取X-Real-IP，如果不存在再从X-Forwarded-For获得第一个IP(用,分割)，
     * 如果还不存在则调用Request .getRemoteAddr()。
     *
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        if (isEmpty(request)) {
            return "";
        }
        String ip = request.getHeader("X-Real-IP");
        if (ip != null && !"".equals(ip) && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getHeader("X-Forwarded-For");
        if (ip != null && !"".equals(ip) && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个IP值，第一个为真实IP。
            int index = ip.indexOf(',');
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        } else {
            return request.getRemoteAddr();
        }
    }

    /**
     * 获取来访者的浏览器版本
     *
     * @param request
     * @return
     */
    public static String getRequestBrowserInfo(HttpServletRequest request) {
        String browserVersion = null;
        String header = request.getHeader("user-agent");
        if (isEmpty(header)) {
            return "";
        }
        if (header.indexOf("MSIE") > 0) {
            browserVersion = "IE";
        } else if (header.indexOf("Firefox") > 0) {
            browserVersion = "Firefox";
        } else if (header.indexOf("Chrome") > 0) {
            browserVersion = "Chrome";
        } else if (header.indexOf("Safari") > 0) {
            browserVersion = "Safari";
        } else if (header.indexOf("Camino") > 0) {
            browserVersion = "Camino";
        } else if (header.indexOf("Konqueror") > 0) {
            browserVersion = "Konqueror";
        }
        return browserVersion;
    }

    /**
     * 获取系统版本信息
     *
     * @param request
     * @return
     */
    public static String getRequestSystemInfo(HttpServletRequest request) {
        String systenInfo = null;
        String header = request.getHeader("user-agent");
        if (isEmpty(header)) {
            return "";
        }
        //得到用户的操作系统
        if (header.indexOf("NT 6.0") > 0) {
            systenInfo = "Windows Vista/Server 2008";
        } else if (header.indexOf("NT 5.2") > 0) {
            systenInfo = "Windows Server 2003";
        } else if (header.indexOf("NT 5.1") > 0) {
            systenInfo = "Windows XP";
        } else if (header.indexOf("NT 6.0") > 0) {
            systenInfo = "Windows Vista";
        } else if (header.indexOf("NT 6.1") > 0) {
            systenInfo = "Windows 7";
        } else if (header.indexOf("NT 6.2") > 0) {
            systenInfo = "Windows Slate";
        } else if (header.indexOf("NT 6.3") > 0) {
            systenInfo = "Windows 9";
        } else if (header.indexOf("NT 5") > 0) {
            systenInfo = "Windows 2000";
        } else if (header.indexOf("NT 4") > 0) {
            systenInfo = "Windows NT4";
        } else if (header.indexOf("Me") > 0) {
            systenInfo = "Windows Me";
        } else if (header.indexOf("98") > 0) {
            systenInfo = "Windows 98";
        } else if (header.indexOf("95") > 0) {
            systenInfo = "Windows 95";
        } else if (header.indexOf("Mac") > 0) {
            systenInfo = "Mac";
        } else if (header.indexOf("Unix") > 0) {
            systenInfo = "UNIX";
        } else if (header.indexOf("Linux") > 0) {
            systenInfo = "Linux";
        } else if (header.indexOf("SunOS") > 0) {
            systenInfo = "SunOS";
        }
        return systenInfo;
    }

    /**
     * 获取来访者的主机名称
     *
     * @param ip
     * @return
     */
    public static String getHostName(String ip) {
        InetAddress inet;
        try {
            inet = InetAddress.getByName(ip);
            return inet.getHostName();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 命令获取mac地址
     *
     * @param cmd
     * @return
     */
    private static String callCmd(String[] cmd) {
        String result = "";
        String line = "";
        try {
            Process proc = Runtime.getRuntime().exec(cmd);
            InputStreamReader is = new InputStreamReader(proc.getInputStream());
            BufferedReader br = new BufferedReader(is);
            while ((line = br.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * @param cmd     第一个命令
     * @param another 第二个命令
     * @return 第二个命令的执行结果
     */

    private static String callCmd(String[] cmd, String[] another) {
        String result = "";
        String line = "";
        try {
            Runtime rt = Runtime.getRuntime();
            Process proc = rt.exec(cmd);
            proc.waitFor(); // 已经执行完第一个命令，准备执行第二个命令
            proc = rt.exec(another);
            InputStreamReader is = new InputStreamReader(proc.getInputStream());
            BufferedReader br = new BufferedReader(is);
            while ((line = br.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * @param ip           目标ip,一般在局域网内
     * @param sourceString 命令处理的结果字符串
     * @param macSeparator mac分隔符号
     * @return mac地址，用上面的分隔符号表示
     */

    private static String filterMacAddress(final String ip, final String sourceString, final String macSeparator) {
        String result = "";
        String regExp = "((([0-9,A-F,a-f]{1,2}" + macSeparator + "){1,5})[0-9,A-F,a-f]{1,2})";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(sourceString);
        while (matcher.find()) {
            result = matcher.group(1);
            if (sourceString.indexOf(ip) <= sourceString.lastIndexOf(matcher.group(1))) {
                break; // 如果有多个IP,只匹配本IP对应的Mac.
            }
        }
        return result;
    }

    /**
     * @param ip 目标ip
     * @return Mac Address
     */

    private static String getMacInWindows(final String ip) {
        String result = "";
        String[] cmd = {"cmd", "/c", "ping " + ip};
        String[] another = {"cmd", "/c", "arp -a"};
        String cmdResult = callCmd(cmd, another);
        result = filterMacAddress(ip, cmdResult, "-");
        return result;
    }

    /**
     * @param ip 目标ip
     * @return Mac Address
     */
    private static String getMacInLinux(final String ip) {
        String result = "";
        String[] cmd = {"/bin/sh", "-c", "ping " + ip + " -c 2 && arp -a"};
        String cmdResult = callCmd(cmd);
        result = filterMacAddress(ip, cmdResult, ":");
        return result;
    }

    /**
     * 获取MAC地址
     *
     * @return 返回MAC地址
     */
    public static String getMacAddress(String ip) {
        String macAddress = "";
        macAddress = getMacInWindows(ip).trim();
        if (macAddress == null || "".equals(macAddress)) {
            macAddress = getMacInLinux(ip).trim();
        }
        return macAddress;
    }

    /**
     * 生成excel 文件
     *
     * @param dataRelation LinkedHashMap<String,String> relation = new LinkedHashMap<>();
     *                     relation.put("商品名称","productName");
     * @param data
     * @param path
     */
    public static void createExcel(LinkedHashMap<String, String> dataRelation, List data, String path, String fileName, String sheetName) {
        if (isEmpty(dataRelation)) {
            throw CustomizeRuntimeException.exception("没有设置导出关系");
        }

        if (isEmpty(data)) {
            throw CustomizeRuntimeException.exception("导出数据为空");
        }
        if (isEmpty(path)) {
            throw CustomizeRuntimeException.exception("导出路径错误");
        }
        if (!(path.endsWith("/") || path.endsWith("\\"))) {
            path = path + File.separator;
        }
        if (isEmpty(fileName)) {
            throw CustomizeRuntimeException.exception("导出文件名错误");
        }
        WritableWorkbook wwb = null;
        OutputStream os = null;
        try {
            File folder = new File(path);
            if (!folder.exists() && !folder.isDirectory()) {
                log.info("文件路径不存在: {}", path);
                folder.setReadable(true);
                folder.setExecutable(true);
                folder.setWritable(true);
                folder.mkdirs();
            }
            // 输出的excel的路径
            String filePath = path + fileName;
            File file = new File(filePath);
            if (!file.exists()) {//判断文件目录的存在
                file.setReadable(true);
                file.setExecutable(true);
                file.setWritable(true);
                file.createNewFile();
            }
            log.info("生成文件开始:{}", filePath);
            // 新建立一个jxl文件
            os = new FileOutputStream(filePath);
            // 创建Excel工作薄
            wwb = Workbook.createWorkbook(os);
            // 添加第一个工作表并设置第一个Sheet的名字
            WritableSheet sheet = wwb.createSheet(StringUtils.isBlank(sheetName) ? "Sheet1" : sheetName, 0);
            int lineIndex = 0;
            for (String title : dataRelation.keySet()) {
                // Label(x,y,z) 代表单元格的第x+1列，第y+1行, 内容z
                // 在Label对象的子对象中指明单元格的位置和内容
                Label label = new Label(lineIndex, 0, title);
                // label = new Label(i, 0, title[i]);
                // 将定义好的单元格添加到工作表中
                sheet.addCell(label);
                lineIndex++;
            }

            for (int rowIndex = 0; rowIndex < data.size(); rowIndex++) {
                lineIndex = 0;//每一次都从第一行开始
                Object row = data.get(rowIndex);//当前行的数据
                for (String key : dataRelation.values()) {
                    Object line = null;
                    if (row instanceof Map) {
                        line = ((Map) row).get(key);
                    } else {
                        line = getFieldValue(row, key);
                    }
                    Label label = new Label(lineIndex, rowIndex + 1, isEmptyReturnEmpty(line));
                    sheet.addCell(label);
                    lineIndex++;
                }
            }
            log.info("生成文件结束:{}", filePath);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw CustomizeRuntimeException.exception("文件生成失败");
        } finally {
            try {
                os.flush();
                // 写入数据
                wwb.write();
                // 关闭文件
                wwb.close();
                os.close();
            } catch (Exception e2) {
                log.error(e2.getMessage(), e2);
            }

        }


    }

    /****************** 关 sql 和数据库打交道的 统一用 db 开头 ********************/
    /**
     * 1 null return null <br/>
     * 2 Integer 1 return 1  <br/>
     * 3 String abc return 'abc'  <br/>
     * 4 Date date return 'yyyy-MM-dd HH:mm:ss'  <br/>
     *
     * @param obj
     * @return
     */
    public static String dbGetSqlValueByObject(Object obj) {
        if (isEmpty(obj)) {
            return null;
        } else if (isNumberForObject(obj)) {
            return obj.toString();
        } else if (isTimeForObject(obj)) {
            Date date = (Date) obj;
            String format = convertDateToString(date, COMMON_DATE_FORMAT);
            return "'" + format + "'";
        } else {
            return "'" + obj + "'";
        }
    }

    /**
     * @param str
     * @return
     * @example c.BsIs-->c.bs_is
     * @example abcD-->abc_d
     * @example AbcD-->abc_d
     */
    public static String dbGetSqlFieldByClass(String str) {
        if (str.contains(".")) {
            str = str.split("\\.")[0] + "." + CommonUtil.dbHumpToDB(str.split("\\.")[1]);
        } else {
            str = CommonUtil.dbHumpToDB(str);
        }
        return str;
    }

    /**
     * @param clazz
     * @return
     * @throws Exception
     * @example String return VARCHAR;
     * @example BigDecimal return NUMERIC;
     * ....
     */
    public static String dbJavaTypeToDbType(Class clazz) throws Exception {
        if (clazz.equals(String.class)) {
            return "VARCHAR";
        } else if (clazz.equals(BigDecimal.class)) {
            return "NUMERIC";
        } else if (clazz.equals(Boolean.class) || clazz.equals(boolean.class)) {
            return "BIT";
        } else if (clazz.equals(Integer.class) || clazz.equals(int.class)) {
            return "INTEGER";
        } else if (clazz.equals(Long.class) || clazz.equals(long.class)) {
            return "BIGINT";
        } else if (clazz.equals(Float.class) || clazz.equals(float.class)) {
            return "REAL";
        } else if (clazz.equals(Double.class) || clazz.equals(double.class)) {
            return "DOUBLE";
        } else if (clazz.equals(Byte[].class) || clazz.equals(byte[].class)) {
            return "VARBINARY";
        } else if (clazz.equals(java.sql.Date.class) || clazz.equals(Date.class)) {
            return "TIMESTAMP";
        } else if (clazz.equals(Time.class)) {
            return "TIMESTAMP";
        } else if (clazz.equals(Timestamp.class)) {
            return "TIMESTAMP";
        } else {
            throw new Exception("java类--->" + clazz + "没有找到对应的数据库属性");
        }
    }

    /**
     * @return
     * @throws Exception
     * @example CHAR return String.class
     * @example CHAR return String.class
     * @example VARCHAR return String.class
     * @example NUMERIC return BigDecimal.class
     * .....
     */
    public static Class dbForDBTypeToJavaClass(String dbType) throws Exception {
        if ("CHAR".equals(dbType)) {
            return String.class;
        } else if ("VARCHAR".equals(dbType)) {
            return String.class;
        } else if ("LONGVARCHAR".equals(dbType)) {
            return String.class;
        } else if ("NUMERIC".equals(dbType)) {
            return BigDecimal.class;
        } else if ("DECIMAL".equals(dbType)) {
            return BigDecimal.class;
        } else if ("BIT".equals(dbType)) {
            return Boolean.class;
        } else if ("TINYINT".equals(dbType)) {
            return Byte.class;
        } else if ("SMALLINT".equals(dbType)) {
            return Short.class;
        } else if ("INTEGER".equals(dbType)) {
            return Integer.class;
        } else if ("BIGINT".equals(dbType)) {
            return Long.class;
        } else if ("REAL".equals(dbType)) {
            return Float.class;
        } else if ("FLOAT".equals(dbType)) {
            return Double.class;
        } else if ("DOUBLE".equals(dbType)) {
            return Double.class;
        } else if ("BINARY".equals(dbType)) {
            return Byte[].class;
        } else if ("VARBINARY".equals(dbType)) {
            return Byte[].class;
        } else if ("LONGVARBINARY".equals(dbType)) {
            return Byte[].class;
        } else if ("DATE".equals(dbType)) {
            return Date.class;
        } else if ("TIME".equals(dbType)) {
            return Date.class;
        } else if ("TIMESTAMP".equals(dbType)) {
            return Date.class;
        } else if ("DATETIME".equals(dbType)) {
            return Date.class;
        } else if ("INT".equals(dbType)) {
            return Integer.class;
        } else {
            throw new Exception("dbTypeToJava:数据库类型--->" + dbType + "没有找到对应的java类");
        }
    }

    /**
     * bd_item_info--->BdItemInfo
     *
     * @param
     * @return String
     */
    public static String dbForDBToHump(String str) {
        StringBuffer sb = new StringBuffer();
        String[] fields = str.split("_");
        String temp = null;
        for (int i = 0; i < fields.length; i++) {
            temp = fields[i].trim();
            sb.append(temp.substring(0, 1).toUpperCase()).append(temp.substring(1));
        }
        return sb.toString();
    }

    /**
     * BdItemInfo--->bd_item_info或者bdItemInfo--->bd_item_info
     *
     * @return String
     */
    public static String dbHumpToDB(String str) {
        String first = str.substring(0, 1).toLowerCase();
        String last = str.substring(1);
        StringBuilder tmp = new StringBuilder();
        for (int i = 0; i < last.length(); i++) {
            if (Character.isUpperCase(last.charAt(i))) {
                tmp.append("_" + last.substring(i, i + 1).toLowerCase());
            } else {
                tmp.append(last.substring(i, i + 1));
            }
        }
        return first + tmp.toString();
    }

    /**
     * bd_item_info--->bdItemInfo
     *
     * @return String
     */
    public static String dbForDBToFistLowercaseHump(String str) {
        str = str.toLowerCase();
        StringBuffer sb = new StringBuffer();
        String[] fields = str.split("_");
        String temp = null;
        for (int i = 0; i < fields.length; i++) {
            temp = fields[i].trim();
            if (i == 0) {
                sb.append(temp.substring(0, 1).toLowerCase()).append(temp.substring(1));
            } else {
                sb.append(temp.substring(0, 1).toUpperCase()).append(temp.substring(1));
            }
        }
        return sb.toString();
    }

    /**
     * 获取申请单编号
     *
     * @return
     */
    public static String getApplicationFormNo() {
        String id = "";
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
        String temp = sf.format(new Date());
        int random = (int) (Math.random() * 10000);
        id = temp + random;
        return id;
    }

    /**
     * 自动生成检索编号
     */
    /*public static String getSearchCode() {
        String code = "";
        StringBuffer sb = new StringBuffer();
        // 三个大写英文字母
		for (int n = 0; n < 3; n++) {
			int i = (int) Math.round(Math.random() * 25);
			int j = (int) 'A' + i;
			char ch = (char) j;
			sb.append(ch);
		}
        SimpleDateFormat sf = new SimpleDateFormat(("yyyyMMddHHmmss"));
        String temp = sf.format(new Date());
        code = sb.toString() + temp;
        return code;
    }*/

	/**
	 * 将数字转化为 00001  格式 并拼接
	 * @param sb
	 * @param max    1000
	 * @param count
	 * @return
	 */
	public static String formatNumber(StringBuilder sb, Integer max, Integer count) {
		if (!sb.toString().equals(Constant.PARENT_PROJECT_PREFIX)) {
			//拿到年月
			String currentTime = getCurrentDateTimeByFormat("yyyyMMddHHmmss");
			sb.append(currentTime);
			return sb.toString();
		}
		while (max != 0) {
			sb.append(count / max);
			count = count % max;
			max = max / 10;
		}
		return sb.toString();
	}
}
